#define _CRT_SECURE_NO_WARNINGS 1
//一：翻译环境
//编译阶段（预编译 - 》  编译 - 》 汇编）
//链接阶段（不再细分）
//
//预编译阶段：（文本操作，一些边边角角的东西）
//注释的删除
//头文件的包含 （预处理指令）
//#define 符号的替换（预处理指令）
//所有的预处理指令都是在预处理阶段处理
//
//编译阶段：
//把C语言代码翻译成了汇编指令
//语法分析
//词法分析
//语义分析
//符号汇总
//
//
//汇编阶段：
//将汇编代码翻译成了二进制的指令，变成了目标文件，该文件按照ELF这种文件格式（将一个文件分成各个段）来存储的
//形成符号表
//
//链接阶段 :
//
//将汇编阶段生成的.o文件和链接库，一起生成了可执行程序
//合并段表
//
//外部函数的声明：就是因为在编译期间，生成了符号，产生了符号表，链接期间在汇总到一个符号表中，然后才能通过这个符号表中有效的地址查找到这个函数
//
//二：运行环境
//。。。。。。
//
//三：预编译的详解
//
//预定义符号
//
//过长的行，分成2行的时候，可能会错，所以常加上\  ，这叫续行浮，本质是注释掉回车键
//
//#define 语句后面不能加分53F7
//
//
//#define 机制包括了一个规定，允许把参数替换到文本中，不作任何转换，直接替换，所以括号非常重要！这种实现通常称为宏（macro）或定义
//宏（define macro）。
//
//参数列表的左括号必须与name紧邻。
//如果两者之间有任何空白存在，参数列表就会被解释为stuff的一部分
//
//所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号，避免在使用宏时由于参数中
//的操作符或邻近操作符之间不可预料的相互作用。
//也就是参数带括号，然后整体再带括号！！
//
//2.2.3 #define 替换规则
//在程序中扩展#define定义符号和宏时，需要涉及几个步骤。
//1. 在调用宏时，首先对参数进行检查，看看是否包含任何由#define定义的符号。如果是，它们首先
//被替换。
//2. 替换文本随后被插入到程序中原来文本的位置。对于宏，参数名被他们的值所替换。
//3. 最后，再次对结果文件进行扫描，看看它是否包含任何由#define定义的符号。如果是，就重复上
//述处理过程。
//注意：
//1. 宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏，不能出现递归！！！！！！。
//2. 当预处理器搜索#define定义的符号的时候，字符串常量的内容并不被搜索并替换。比如printf（“M = ：”，M）, 第一个M不会被搜索，第二个才会！！
//
//
//# 和##
//
//如何把一个参数插入到宏的字符串中
//
//使用 # ，把一个宏参数变成对应的字符串
//
//## 的作用
//##可以把位于它两边的符号合成一个符号。
//它允许宏定义从分离的文本片段创建标识符。
//
//当宏参数在宏的定义中出现超过一次的时候，如果参数带有副作用，那么你在使用这个宏的时候就可能
//出现危险，导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。
//
//
//那为什么不用函数来完成这个任务？
//原因有二：
//1. 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。
//所以宏比函数在程序的规模和速度方面更胜一筹。
//2. 更为重要的是函数的参数必须声明为特定的类型。
//所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以
//用于 > 来比较的类型。
//宏是类型无关的。
//
//宏的缺点：当然和函数相比宏也有劣势的地方：
//1. 每次使用宏的时候，一份宏定义的代码将插入到程序中。除非宏比较短，否则可能大幅度增加程序
//的长度。
//2. 宏是没法调试的。
//3. 宏由于类型无关，也就不够严谨。
//4. 宏可能会带来运算符优先级的问题，导致程容易出现错。
//
//宏的有些能力函数是一定没有的
//
//比如接收的参数是类型的能力
//
//宏和函数的对比

